package singleton;

/**
 * 1、懒汉式，线程不安全   单null检查
 * 是否 Lazy 初始化：是
 *
 * 是否多线程安全：否
 *
 * 实现难度：易
 *
 * 描述：这种方式是最基本的实现方式，这种实现最大的问题就是不支持多线程。
 * 因为没有加锁 synchronized，所以严格意义上它并不算单例模式。
 * 这种方式 lazy loading 很明显，不要求线程安全，在多线程不能正常工作。
 */

public class SingletondemoOne {
    private static SingletondemoOne instance;
    // 创建新实例时，控制台会打印出 创建实例
    private SingletondemoOne(){
        System.out.println("SingletondemoOne 创建实例");
    }
    /**
     * 之所以线程不安全是因为当多线程情况下 ：假如有两个线程 a ，b
     * 当线程a执行到 new SingletondemoOne() 时，线程b执行到if(instance == null)，
     * 因为是懒加载，此时实例还没有创建 所以 instance == null
     * 然后线程b也执行到 new SingletondemoOne();
     * 然后结果会创建两个实例，所以在多线程的情况下 线程不安全！！！！！！ 而且通过反射也可以创建新的实例
     */
    public static SingletondemoOne getInstance(){
        if(instance == null){
            return new SingletondemoOne();
        }
        return instance;
    }

    //那么把同步锁加上呢？那么加哪呢？
    /**
     *    synchronized
     *    1. 修饰一个代码块，被修饰的代码块称为同步语句块，其作用的范围是大括号{}括起来的代码，作用的对象是调用这个代码块的对象；
     *    2. 修饰一个方法，被修饰的方法称为同步方法，其作用的范围是整个方法，作用的对象是调用这个方法的对象；
     *    3. 修饰一个静态的方法，其作用的范围是整个静态方法，作用的对象是这个类的所有对象；
     *    4. 修饰一个类，其作用的范围是synchronized后面括号括起来的部分，作用主的对象是这个类的所有对象。
     */
    // 这样？
    public static SingletondemoOne getInstanceTwo(){
        if(instance == null){
            synchronized(SingletondemoOne.class){
                return new SingletondemoOne();
            }

        }
        return instance;
    }
    // 还是不行，原因和上面一样，只不过停在锁上面

    // 那把同步锁加在方法上？
    public static synchronized SingletondemoOne getInstanceThree(){
        if(instance == null){
                return new SingletondemoOne();
        }
        return instance;
    }
    // 这样可以！！！，但是因为锁加在了方法上，线程是安全了，
    // 但是却极大的降低了性能，因为大部分情况下线程都只是去获取这个实例，但现在却要排队。
    // 用锁能解决，但是得看SingletondemoTwo!!!!!!
}

